<template>
  <el-card :body-style="{height:'100%'}" shadow="hover" style="height: 100%;">
    <template #header>
      大文件上传,断点续传

      <el-link type="primary" target="_blank" href="https://www.npmjs.com/package/p-limit">请求并发的限制</el-link>
    </template>
    <el-upload :http-request="httpRequest" action="#">
      <template #trigger>
        <el-button type="primary">上传</el-button>
      </template>
      <template #tip>
        <el-progress :percentage="percentage"/>
      </template>
    </el-upload>


    <pre>
      前后端实现思路
      首先前端获取到要上传的大文件,使用SparkMd5库进行文件哈希值计算(为做断点续传)
      计算文件哈希不做全量计算否则文件过大,计算非常慢,做抽样哈希,
      然后进行切片,对每个文件以哈希值加切片索引命名
      然后后端需要提供三给接口
      1.获取已上传文件列表的接口(保护文件名和文件大小)
      2.文件上传的接口
      3.文件合并的接口
      然后上传,上传过程中出现断网情况,重新上传时前端更具后端的检查文件接口进行过滤已经上传的文件

      请求并发的限制
    </pre>


  </el-card>
</template>

<script lang="ts" name="largeFile-upload" setup>
import {UploadRequestOptions} from "element-plus";
import {getFinishChunkListApi, getMergeFileApi, getBigFileUploadApi} from "@/api/file";
import {generateChunk} from "@/utils/file";
import {ElMessage} from 'element-plus'
import {concurrency} from '@/service/limit'
import {differenceWith} from 'lodash-es'

// import pLimit from 'p-limit';



let percentage = shallowRef(0)
let finishLength = 0

const httpRequest = async ({file}: UploadRequestOptions) => {
  //文件切片
  const chunkList = await generateChunk(file)
  console.log(chunkList,'文件切片')
  //获取已上传切片
  const {finishChunk} = await getFinishChunkListApi()
  console.log(finishChunk,'获取已上传切片')
  const uploadFile = differenceWith(chunkList, finishChunk,(a,b) => a.filename === b.filename && a.file.size === b.size)

  console.log(uploadFile,'需要上传')

  finishLength = chunkList.length - uploadFile.length

  console.log(finishLength)

  percentage.value = parseFloat((finishLength / chunkList.length * 100).toFixed(2))

  const requestList = uploadFile.map(file => getBigFileUploadApi.bind(null, file))

  // 并发限制
  await concurrency(requestList, 3, () => {
    finishLength++
    percentage.value = parseFloat((finishLength / chunkList.length * 100).toFixed(2))
    if (chunkList.length === finishLength) {
      getMergeFileApi().then(res => {
        ElMessage({
          message: res.message,
          type: 'success',
        })
      })
    }
  }, (error) => console.log(error))
}

</script>

<style lang="less" scoped>

</style>
